package com.check;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.utils.SpringContextUtil;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.text.MessageFormat;
import java.util.*;


@WebFilter(urlPatterns = {"/*"}, filterName = "checkFilter")
public class CheckFilter implements Filter {

	@Value("${local.language}")
	private String language;

	@Value("${local.country}")
	private String country;

	@Override
	public void init(FilterConfig filterConfig) {
		System.out.println("过滤器初始化");
	}

	@Override
	public void destroy() {
		System.out.println("过滤器销毁");
	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		String path = ((HttpServletRequest)servletRequest).getRequestURI().substring(((HttpServletRequest) servletRequest).getContextPath().length());
		System.out.println("过滤器url:"+path);
		ConfigurationEnum configDetail = ConfigurationEnum.getConfiguration(path);
		//如果该路径没有配置验证则跳过验证，进入下一步
		if(configDetail == ConfigurationEnum.UNDEFINED){
			filterChain.doFilter(servletRequest, servletResponse);
		}else{
			HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
			String method = httpServletRequest.getMethod();
			String contentType = httpServletRequest.getContentType().toUpperCase();//转成大写
			//如果请求方式是POST,类型为APPLICATION/JSON进入验证，否则跳过验证
			if("POST".equals(method) && "APPLICATION/JSON".equals(contentType)){
				HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
				httpServletResponse.setCharacterEncoding("UTF-8");
				httpServletResponse.setContentType("application/json; charset=utf-8");
				ServletRequest requestWrapper = new RequestWrapper(httpServletRequest);
				String body = HttpHelper.getBodyString(requestWrapper);
				String param = URLDecoder.decode(body,"utf-8");
				ObjectMapper mapper = new ObjectMapper();
				Map<String,Object> paramMap = mapper.readValue(param, Map.class);

				Map resultMap = validateData(paramMap, configDetail);
				//验证没有通过
				if(resultMap.size() > 0){
					JSONObject json = JSONObject.fromObject(resultMap);
					ServletOutputStream out = servletResponse.getOutputStream();
					out.write(json.toString().getBytes());
					out.flush();
				}else{//验证通过，继续访问controller
					//必须调用这个，否则controller拿不到参数
					filterChain.doFilter(requestWrapper, servletResponse);
				}
			}else{//get请求直接放行
				filterChain.doFilter(servletRequest, servletResponse);
			}
		}
	}

	/***
	 * 验证数据
	 * @param paramMap
	 * @param configDetail
	 * @return
	 */
	private Map validateData(Map paramMap, ConfigurationEnum configDetail){
		Map resultMap = new HashMap();
		//请求路径
		String url = configDetail.getUrl();
		//验证类Service
		String fullPathClazz = configDetail.getFullPathClazz();
		//验证类Service方法
		String methodName = configDetail.getMethodName();
		//被验证的目标对象
		String objectClazz = configDetail.getObjectClazz();
		try {
			Class seviceClass = Class.forName(fullPathClazz);
			Class objectClass = Class.forName(objectClazz);
			//Object seviceObject = seviceClass.newInstance();//通过反射获取，service中dao为null
			//改成通过spring上下文获取，这样才能获取service中的dao
            Object seviceObject = SpringContextUtil.getBean(seviceClass);
			Method method = seviceClass.getMethod(methodName, objectClass);// 获取空参数一般方法。
			Object validateObj = map2Object(paramMap, objectClass);//把map转成验证对象
			Object validateResult = method.invoke(seviceObject, validateObj);
			resultMap = languageTransformation((Map) validateResult);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return resultMap;
	}

	/**
	 * 返回信息根据配置语言环境转换
	 * @param paramMap
	 */
	private Map languageTransformation(Map<String,String> paramMap){
		Map map = new HashMap();
		//Locale  locale_cn = new Locale("zh", "CN");
		//Locale  locale_us = new Locale("en", "US");
		//Locale  locale_jp = new Locale("ja", "JP");
		Locale  locale = new Locale(language, country);
		ResourceBundle res = ResourceBundle.getBundle("i18n.info", locale);
		for (Map.Entry<String, String> entry : paramMap.entrySet()) {
			System.out.println(entry.getKey() + ": " + entry.getValue());
			String key = entry.getKey();
			String value = entry.getValue();
			//带占位符
			String contentPlaceHolder = res.getString(value);
			//替换占位符
			String completion = MessageFormat.format(contentPlaceHolder, key);
			map.put(key,completion);
		}
		return map;
	}

	/***
	 * map -> json -> object
	 * @param map
	 * @return
	 */
	private Object map2Object(Map map, Class objectClass){
		JSONObject json = JSONObject.fromObject(map);
		Object obj = JSONObject.toBean(json, objectClass);
		return obj;
	}

}
